Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

import environment variables that are present #1019

Merged
merged 3 commits into from
Jul 16, 2018

Conversation

ktomk
Copy link
Contributor

@ktomk ktomk commented Apr 22, 2018

fixes docker/for-linux#284

previously docker did import environment variables if they were present
but created them if they were not when it was asked via a --env-file
cli option to import but not create them.

fix is to only import the variable into the environment if it is present.

additionally do not import variable names of zero-length (which are lines
w/ a potential variable definition w/o a variable name).

refs:

- What I did

  1. Check for environment variable presence and only import if it is present.

  2. Check the environment variable is not with a zero-length name

- How I did it

  1. Swap os.Getenv w/ os.LookupEnv for emptyFn to gain presence information and handle it

  2. String length check

- How to verify it

I have not run any automated test on these apart from the existing build. I'm new to go so I'm not yet comfortable adding tests.

- Description for the changelog

Fix environment file parsing for imports of absent variables and those w/ no name.

@ktomk
Copy link
Contributor Author

ktomk commented Apr 22, 2018

I need some assistance w/ this PR: I reported the issue in the docker-linux repository and I don't know if that is the right location as I could identfiy the cli repository to create the PR later so was unsure whether or not it is necessary to re-create the issue or how to cross-link it in the description.

Copy link
Collaborator

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM 🐯

@thaJeztah
Copy link
Member

Thanks! I double checked the expected behavior as I know there were some oddities in this in the past 😅

From the documentation: set environment variables (-e, --env, --env-file)

When running the command, the Docker CLI client checks the value the variable has in your local environment and passes it to the container. If no = is provided and that variable is not exported in your local environment, the variable won’t be set in the container.

Using the -e / --env option seems to match that behavior (removed the default HOME, PATH, and HOSTNAME vars in the output):

export FROMENVIRONMENT=blabla

docker run --rm -e FROMENVIRONMENT -e NOSUCHVAR -e NOSUCHWITHEQUAL= busybox env

FOOBAR=blabla
NOSUCHWITHEQUAL=

But doing the same through an env-file indeed produces a different result:

cat <<EOF > myenv
FROMENVIRONMENT
NOSUCHVAR
NOSUCHWITHEQUAL=
EOF
docker run --rm --env-file ./myenv busybox env

FROMENVIRONMENT=
NOSUCHVAR=
NOSUCHWITHEQUAL=

Testing with this patch correctly produces

docker run --rm --env-file ./myenv busybox env

FROMENVIRONMENT=blabla
NOSUCHWITHEQUAL=

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some minor nits, but would like to see a test / integration test for this.

There were some tests in the Moby repository, but those were removed there after the CLI moved to its own repository (see moby/moby#33511)

@vdemeester do you know if new tests were added in this repository to replace those?

opts/file.go Outdated
if emptyFn != nil {
value = emptyFn(line)
value, boolean = emptyFn(line)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

boolean is a bit odd for the variable name; perhaps change to something like exists or isSet

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure for the rename.

For the tests I need some assistance but I'm eager to add some / extend existing ones, I just need some guidance into.

@@ -53,17 +53,23 @@ func parseKeyValueFile(filename string, emptyFn func(string) string) ([]string,
if strings.ContainsAny(variable, whiteSpaces) {
return []string{}, ErrBadKey{fmt.Sprintf("variable '%s' has white spaces", variable)}
}
if len(variable) == 0 {
return []string{}, ErrBadKey{fmt.Sprintf("no variable name on line '%s'", line)}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also testing the validation, using this env-file;

FROMENVIRONMENT
# this is a comment
NOSUCHVAR
NOSUCHWITHEQUAL=
# empty line:

# whitespace-only line (spaces):
     
# whitespace-only line (tabs):
				
# whitespace-only line (tabs + spaces):
	 	 	
# starts with = (invalid)
=nothing
EOF
$ docker run --rm --env-file ./myenv busybox env
docker: poorly formatted environment: no variable name on line '=nothing'.
See 'docker run --help'.

Copy link
Contributor Author

@ktomk ktomk Jul 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the test for the fix in question before the fix. signed both commits. I rbased fresh on master, I guess this goes easily into the RC but I don't know of the Docker projects internal workflow regarding versioning, so just FYI. Let me know if you'd like to get TESTING.md cleaned up or about any back ports.

Copy link
Contributor

@silvin-lubecki silvin-lubecki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -53,17 +53,23 @@ func parseKeyValueFile(filename string, emptyFn func(string) string) ([]string,
if strings.ContainsAny(variable, whiteSpaces) {
return []string{}, ErrBadKey{fmt.Sprintf("variable '%s' has white spaces", variable)}
}
if len(variable) == 0 {
return []string{}, ErrBadKey{fmt.Sprintf("no variable name on line '%s'", line)}
}

if len(data) > 1 {
// pass the value through, no trimming
lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1]))
} else {
var value string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

if emptyFn != nil{
    if value, isSet := emptyFn(line); isSet{
        // if only a pass-through variable is given, clean it up.
        lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), value))
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not suggested within POSIX that a well-formed variable name may contain a space character, however: "Other characters may be permitted by an implementation; applications shall tolerate the presence of such names." - so either refuse or accept but not alter (like trimming spaces). (quote from: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least needs tests against emptyFn() implementation how it deals with such thought-to-be-trim-able variable names as it is used to acquire the value. The behavior must then be same.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we had some validation in the past, but there's no strict rule what's "allowed" as variable name, so we decided to remove validation and leave it to the container's process to decide what's valid and what not.

Having said the above; trimming trailing whitespace in variable names could be an exception (i.e., I don't think it's possible to define a var with leading/trailing whitespace, as the whitespace would be stripped by the shell), but I'm not sure we should; for example, the following would produce an error in your shell as well;

$ export foo = bar
bash: export: `=': not a valid identifier

Leading whitespace in the value leads to "no value being set";

$ export bar=    bar
$ env | grep bar
bar=

This looks to be something where we differ, because the shell requires quotes for that:

$ export baz="     bla"
$ env | grep baz
baz=     bla

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My nit was only a small refactor and should be equivalent with your version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe were you answering to @thaJeztah previous comment 😅

@thaJeztah
Copy link
Member

@ktomk for the tests; I think we need an integration test for this; there are some existing tests in https://github.com/docker/cli/blob/master/e2e/image/build_test.go, which could be a good starting point to look at.

Let me know if that's enough information, or if you need more 👍

@ktomk
Copy link
Contributor Author

ktomk commented May 24, 2018

@thaJeztah: Thanks for the follow up on tests, I'll take a look. From a very first glance, how to invoke (run) a test file then?

/e: after pressing the submit button, reminded me I can check the cicleci test step probably for that info.

@thaJeztah
Copy link
Member

Just recalled we have some docs on that in https://github.com/docker/cli/blob/master/TESTING.md

@ktomk
Copy link
Contributor Author

ktomk commented Jul 1, 2018

@thaJeztah; TESTING.md is lying about package github.com/stretchr/testify/assert, it should be removed from that document, tests aren't even executed w/ it as the package is not even loaded. I don't know if opening a ticket is on your side as you're the reviewer requesting tests based on that wrong information, regardless of what, just from my end, please see it reported by my comment.

ktomk added 3 commits July 2, 2018 07:33
test to show current behavior is wrong at parsing an environment file
defining an undefined variable - it must not be defined!

NOTE: this test assume the $HOME variable is always set (see POSIX, this
      normally is the case, e.g. the test suite remains stable).

Signed-off-by: Tom Klingenberg <tklingenberg@lastflood.net>
previously docker did import environment variables if they were present
but created them if they were not when it was asked via a --env-file
cli option to import but not create them.

fix is to only import the variable into the environment if it is present.

additionally do not import variable names of zero-length (which are lines
w/ a potential variable definition w/o a variable name).

refs:

- docker/for-linux#284

Signed-off-by: Tom Klingenberg <tklingenberg@lastflood.net>
parsing an environment file should give an error in case a zero-length
variable name (definition w/o a variable name) is encountered.

previously these lines went through unnoticed not informing the user about
a potential configuration error.

Signed-off-by: Tom Klingenberg <tklingenberg@lastflood.net>
@docker docker deleted a comment from GordonTheTurtle Jul 2, 2018
@ktomk
Copy link
Contributor Author

ktomk commented Jul 12, 2018

@thaJeztah Please review the tests I added and let me know about any ifs.

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

Copy link
Collaborator

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still LGTM 🐯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants